package db;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.util.ArrayList;

import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;





public class fileParser 
{


	private BufferedReader br ;


	private String[] discid = new String[1];

	private String dtitle;

	private String partist;

	private boolean various = false;


	private ArrayList<String> varArtists = new ArrayList<String>();

	private ArrayList<String> parsed_track_titles = new ArrayList<String>();

	private String ptitle;

	private int dyear;

	private String dgenre;

	private ArrayList<Integer> trackOffsets = new ArrayList<Integer>();

	private int length;

	private ArrayList<String> track_titles = new ArrayList<String>();



	private  boolean isCddbFormat = false;


	/**
	 * Constructs a parser for the given file.
	 * 
	 * @param file
	 * @throws FileNotFoundException 
	 */

	public fileParser(BufferedReader bin) throws FileNotFoundException 
	{
		this.br = bin;
	}



	/**
	 * Close and clean up the parser.
	 */
	public void close() 
	{
		try 
		{
			br.close();

		} 

		catch (IOException e) 
		{
			System.err.println("Error in parser: Couldn't close BufferedReader. " + e);
		}
	}



	public String[] getDiscId() 
	{
		return discid;
	}



	public String getDtitle() 
	{
		return dtitle;
	}


	public String getParsedArtist() 
	{
		return partist;
	}


	public boolean isVarious() 
	{
		return various;
	}




	public ArrayList<String> getVarArtists() 
	{
		return varArtists;
	}



	public ArrayList<String> getParsed_track_titles() {
		return parsed_track_titles;
	}


	public String getParsedTitle() 
	{
		return ptitle;
	}


	public int getDyear() 
	{
		return dyear;
	}


	public String getDgenre() 
	{
		return dgenre;
	}


	public void setDgenre(String genre) 
	{
		dgenre = genre;
	}


	public int getDiscLength() {
		return length;
	}

	public ArrayList<Integer> getTrackOffsets() {
		return trackOffsets;
	}



	public ArrayList<String> getTtitles() 
	{
		return track_titles;
	}





	public int[] calculateTracksLengths(ArrayList<Integer> trackOffsets, int discLenghtSec)
	{
		int length= trackOffsets.size();


		int[] trackLengths = new int[length];

		for (int j=0; j< length -1; j++)
		{


			trackLengths[j]= (trackOffsets.get(j+1) - trackOffsets.get(j)) / 75;

		}

		trackLengths[length -1] = (   discLenghtSec*75 -  trackOffsets.get(length -1)   )  /  75;

		return trackLengths;
	}


	/**
	 * Determine if the file parsed is a CDDB file or not.
	 * @return True if it is a CDDB file, False otherwise
	 * @throws IOException 
	 * @throws NumberFormatException 
	 * @throws InterruptedException 
	 * @throws SAXException 
	 * @throws ParserConfigurationException 
	 * @throws IllegalStateException 
	 */




	public boolean parse() throws NumberFormatException, IOException, IllegalStateException, ParserConfigurationException, SAXException, InterruptedException 
	{
		String line;

		dtitle = "";

		boolean readingTrackOffsets = false;

		while ((line = br.readLine()) != null) 
		{	

			if (line.startsWith("# Disc length: ")) 
			{
				readingTrackOffsets = false;
				String l = line.split(":")[1].substring(1).split(" ")[0];
				if (l.length() !=0)
				{
					String len = line.split(":")[1].substring(1).split(" ")[0];
					if (isNumeric(len))
					{
					length = Integer.parseInt(len);
					}
				}

			}



			else if(line.startsWith(" xmcd"))
			{
				isCddbFormat = true;

			
			}



			else if (line.startsWith("DISCID=")) 
			{
				if (line.indexOf(",") == -1) 
				{
					discid[0] = line.substring(line.indexOf("=")+1);
				}
				else
				{
					discid = line.substring(line.indexOf("=")+1).split(","); 
				}

			} 


			else if (line.startsWith("# Track frame offsets:"))
			{
			
				readingTrackOffsets = true;	


			}

			else if (line.startsWith("DTITLE=")) 
			{
				dtitle += line.substring(line.indexOf("=")+1);
				
				if (dtitle.length() > 255 || dtitle.length() == 0)
				{
					return false;
				}
				
				if ( (dtitle.toLowerCase().contains("various") == true )
						||  (dtitle.toLowerCase().contains("varios") == true )
						||  (dtitle.toLowerCase().contains("varius") == true )
						|| (dtitle.toLowerCase().contains("verious") == true )
						||  (dtitle.toLowerCase().contains("var") == true ))

				{

					this.various = true;
				}
			} 




			else if (line.startsWith("DYEAR=")) 
			{
				int len = line.substring(6).trim().length();
				if (len == 4) 
				{
					String year = line.substring(line.indexOf("=")+1).trim();
					if(isNumeric(year))
					{
					dyear = Integer.parseInt(year);
					if (dyear > 2155 || dyear < 1901) 
					{
						dyear = 0;
					}
					}

				} 

				else 
				{
					dyear = 0;
				}
			} 




			else if (line.startsWith("DGENRE=")) 
			{

				dgenre = line.substring(line.indexOf("=")+1);

				if (dgenre.length() > 255)
				{
					dgenre = null;
				}

				int first_index = 0;
				int second_index=0;
				if (dgenre.indexOf(" / ") >0)
				{
					first_index=dgenre.indexOf(" / ");
					second_index = first_index+3;
				}

				else if(dgenre.indexOf("/") >0)
				{
					first_index=dgenre.indexOf("/");
					second_index = first_index+1;
				}

				else if(dgenre.indexOf("-") >0)
				{
					first_index = dgenre.indexOf("-");
					second_index = first_index+1;
				}

				else if(dgenre.indexOf("+") >0)
				{
					first_index = dgenre.indexOf("+");
					second_index = first_index+1;
				}


				else if (dgenre.indexOf(" + ") >0)
				{
					first_index = dgenre.indexOf(" + ");
					second_index = first_index+3;
				}

				else if(dgenre.indexOf(" , ") >0)
				{
					first_index = dgenre.indexOf(" , ");
					second_index = first_index+3;

				}

				else if(dgenre.indexOf(",") >0)
				{
					first_index = dgenre.indexOf(",");
					second_index = first_index+1;
				}

				else if(dgenre.indexOf(" ; ") >0)
				{
					first_index = dgenre.indexOf(" ; ");
					second_index = first_index+3;
				}

				else if(dgenre.indexOf(";") >0)
				{
					first_index = dgenre.indexOf(";");
					second_index = first_index+1;
				}


				if (first_index >0)
				{

					dgenre = dgenre.substring(0, first_index) + " - " + dgenre.substring(second_index);
				}




				if(dgenre.indexOf(" & ") >0)
				{
					dgenre = dgenre.substring(0, dgenre.indexOf(" & ")) + "&" + dgenre.substring(dgenre.indexOf(" & ")+3);
				}

			} 




			else if (line.startsWith("TTITLE"))
			{

				if (line.indexOf("=") >0)
				{
					String index = line.substring(6, line.indexOf("="));
					if (isNumeric(index))
					{
				int title_index = Integer.parseInt(index);


				if 	(track_titles.size() < title_index + 1) 

				{

					track_titles.add(line.substring(line.indexOf("=")+1));
				} else {
					String str = track_titles.get(title_index);
					str +=line.substring(line.indexOf("=")+1);
					track_titles.set(title_index, str);
				};

				}
				}
			} 




			else if (readingTrackOffsets)
			{
				String trackOffset = line.substring(1).trim();
				if (trackOffset.length() > 1)
				{
					if (isNumeric(trackOffset))
					{
					int Offset = Integer.parseInt(trackOffset);
					trackOffsets.add(Offset);
					}
				}
			}

		}


		// Clean up some values
		
		
		if (track_titles.size() != trackOffsets.size())
		{
			return false;
		}
		

		// removing too long track titles
		ArrayList<String> newTrackTitles = new ArrayList<String>();
		
		for (int i=0; i<track_titles.size(); i++)
		{
			if (track_titles.get(i).length() <= 255 || track_titles.get(i).length() != 0)
			{
				newTrackTitles.add(track_titles.get(i));
			}
		}
		
		track_titles.clear();
		track_titles.addAll(newTrackTitles);
		

		
		if (various == true)
		{
			int numOfTracks = track_titles.size();

			for (int i=0; i< numOfTracks; i++)
			{
				String title_i = track_titles.get(i);
				int t_ind= title_i.indexOf(" / ");
				if (t_ind > 0)
				{
					this.varArtists.add( title_i.substring(0, t_ind).trim()) ;
					this.parsed_track_titles.add( title_i.substring(t_ind+3).trim()) ;
				}

				else
				{
					varArtists = null;
					break;
				}

			}

		}


		if (dtitle.indexOf(" / ") > 0)
		{
		
			int dt_ind = dtitle.indexOf(" / ");
			this.partist = dtitle.substring(0, dt_ind).trim();
			this.ptitle = dtitle.substring(dt_ind+3).trim();
		}



		else

		{
			if (various == true)
			{
				dtitle = "Various";
			}
			ptitle = partist = dtitle;
		}


        if (isCddbFormat() == false || isCDAscii() == false)
        {
                
                return false;
        }


        if (isVarious() == false)
        {
        if (getTtitles().size() < getTrackOffsets().size() 
                        || getTrackOffsets().size() < getTtitles().size())
                        
        {
                
        	 return false;
        }
        }
        
        if (isVarious() == true)
        {
        if ( getParsed_track_titles().size() < getTrackOffsets().size()
                
                        || getTrackOffsets().size() < getParsed_track_titles().size())
        {
                
        	 return false;
        }
        }
        
        




        else if ((isVarious()== true) && (getVarArtists()==null))
        {
        
                return false;
        }
    
		
		
		
		return true;

	}






	public boolean isCddbFormat() {
		return isCddbFormat;
	}



	public void setCddbFormat(boolean isCddbFormat) {
		this.isCddbFormat = isCddbFormat;
	}



	private boolean isStringAscii(String str)
	{

		return str.matches("\\A\\p{ASCII}*\\z");

	}




	public boolean isCDAscii()
	{
		boolean b=true;

		if (    (isStringAscii(discid[0]) == false) || (isStringAscii(dtitle) == false) 
				|| (isStringAscii(partist) == false) || (isStringAscii(ptitle) == false)
				|| (isStringAscii(dgenre) == false))
		{
			b = false;
		}

		else



		{
			if (isVarious() == false)
			{
				for (String s : track_titles)
				{
					if (isStringAscii(s) == false)
					{

						b= false;

					}
				}
			}
	
			else
			{
				if (varArtists != null)
				{
					for (int i =0; i< varArtists.size();i++)
					{
						if (isStringAscii(varArtists.get(i)) == false || isStringAscii(parsed_track_titles.get(i)) == false)
						{
							b = false;
						}
					}
				}
			}

		}

	
		return b;
	}


	
	private boolean isNumeric(String str)
	{
		NumberFormat formatter = NumberFormat.getInstance();
		ParsePosition pos = new ParsePosition(0);
		formatter.parseObject(str, pos);
		return str.length()==pos.getIndex();
	}
	
	
	

}
